/**
 * Copyright 2020 Huawei Technologies Co., Ltd
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef MINDSPORE_CCSRC_OPTIMIZER_IRPASS_GRADIENT_ELIMINATE_H_
#define MINDSPORE_CCSRC_OPTIMIZER_IRPASS_GRADIENT_ELIMINATE_H_

#include <vector>
#include <algorithm>
#include <memory>

#include "optimizer/optimizer.h"
#include "optimizer/irpass.h"
#include "ir/visitor.h"
#include "common/utils.h"
#include "operator/ops.h"
#include "optimizer/ad/grad.h"

namespace mindspore {
namespace opt {
namespace irpass {
namespace internal {
AnfNodePtr ExpandJ(const ValueNodePtr &vnode, const pipeline::ResourceBasePtr &resource);
}  // namespace internal

// {prim::kPrimJ, C}
class ExpandJPrim : public AnfVisitor {
 public:
  AnfNodePtr operator()(const OptimizerPtr &optimizer, const AnfNodePtr &node) override {
    x_ = nullptr;
    AnfVisitor::Match(prim::kPrimJ, {IsVNode})(node);
    if (x_ != nullptr) {
      TraceManager::DebugTrace(std::make_shared<TraceExpandJ>(node->debug_info()));
      auto j_node = internal::ExpandJ(x_, optimizer->resource());
      TraceManager::EndTrace();
      return j_node;
    }
    return nullptr;
  }

  void Visit(const ValueNodePtr &node) override { x_ = node; }

 private:
  ValueNodePtr x_{nullptr};
};

// stop_gradient(x) ==> x
class StopGradientEliminater : public AnfVisitor {
 public:
  AnfNodePtr operator()(const OptimizerPtr &, const AnfNodePtr &node) override {
    x_ = nullptr;
    AnfVisitor::Match(prim::kPrimStopGradient)(node);
    return x_;
  }

  void Visit(const AnfNodePtr &node) override { x_ = node; }

 private:
  AnfNodePtr x_{nullptr};
};
}  // namespace irpass
}  // namespace opt
}  // namespace mindspore
#endif  // MINDSPORE_CCSRC_OPTIMIZER_IRPASS_GRADIENT_ELIMINATE_H_
